package cn.huiyunche.base.service.interfaces.impl;

import cn.huiyunche.base.service.constant.BVehicleConstant;
import cn.huiyunche.base.service.enums.BFeeModelEnum;
import cn.huiyunche.base.service.enums.BFeeTypeEnum;
import cn.huiyunche.base.service.form.VehiClesInfoFrom;
import cn.huiyunche.base.service.interfaces.BFeeModelService;
import cn.huiyunche.base.service.interfaces.BFeeTypeService;
import cn.huiyunche.base.service.interfaces.BVehicleClassService;
import cn.huiyunche.base.service.interfaces.SShippingFeeService;
import cn.huiyunche.base.service.mappers.SShippingFeeMapper;
import cn.huiyunche.base.service.model.*;
import cn.huiyunche.base.service.utils.ValidationParams;
import cn.huiyunche.base.service.vo.PageVo;
import cn.huiyunche.base.service.vo.Result;
import cn.huiyunche.base.service.vo.SOrderFeeDetailVo;
import com.alibaba.fastjson.JSON;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class SShippingFeeServiceImpl implements SShippingFeeService {

    private static final Logger LOGGER = LoggerFactory.getLogger(SShippingFeeServiceImpl.class);

    @Autowired
    private BFeeTypeService bFeeTypeService;

    @Autowired
    private BFeeModelService bFeeModelService;

    @Autowired
    private BVehicleClassService bVehicleClassService;

    @Autowired
    private SShippingFeeMapper sShippingFeeMapper = null;

    public SShippingFeeMapper getSShippingFeeMapper() {
        return this.sShippingFeeMapper;
    }

    /**
     * 更新距离浮动因数
     *
     * @param sShippingFee
     * @return
     */
    @Override
    public Result<String> updateShippingSubsidy(SShippingFee sShippingFee) {
        LOGGER.info("udpate shipping fee subsidy params sShippingFee : {}.", JSON.toJSONString(sShippingFee));
        Result<String> result = new Result<String>(true, null, "更新距离浮动因数完成");
        if (sShippingFee.getId() == null) {
            LOGGER.info("udpate shipping fee subsidy id is not null.");
            result.setSuccess(false);
            result.setMessage("更新距离浮动因数ID不能为空");
            return result;
        } else if (sShippingFee.getSubsidy() == null) {
            LOGGER.info("udpate shipping fee subsidy subsidyparam is not null.");
            result.setSuccess(false);
            result.setMessage("更新距离浮动因数补助不能为空");
            return result;
        }
        try {
            result.setData(this.getSShippingFeeMapper().updateByPrimaryKeySelective(sShippingFee) + "");
        } catch (Exception e) {
            LOGGER.error("udpate shipping fee subsidy error : {}.", e);
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 更新运距系数
     *
     * @param sShippingFee
     * @return
     */
    @Override
    public Result<String> updateShippingRate(SShippingFee sShippingFee) {
        LOGGER.info("udpate shipping fee rate params sShippingFee : {}.", JSON.toJSONString(sShippingFee));
        Result<String> result = new Result<String>(true, null, "更新运距系数完成");
        if (sShippingFee.getId() == null) {
            LOGGER.info("udpate shipping fee rate id is not null.");
            result.setSuccess(false);
            result.setMessage("更新运距系数ID不能为空");
            return result;
        } else if (sShippingFee.getRate() == null) {
            LOGGER.info("udpate shipping fee rate rateparam is not null.");
            result.setSuccess(false);
            result.setMessage("更新运距系数费率不能为空");
            return result;
        }
        try {
            result.setData(this.getSShippingFeeMapper().updateByPrimaryKeySelective(sShippingFee) + "");
        } catch (Exception e) {
            LOGGER.error("udpate shipping fee rate error : {}.", e);
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 查询运距系数 距离浮动因数列表
     *
     * @param page
     * @param sShippingFee
     * @return
     */
    @Override
    public Map<String, Object> list(PageVo page, SShippingFee sShippingFee) {
        LOGGER.info("select shipping fee list params pageL{}, sShippingFee:{}.", JSON.toJSONString(page), JSON.toJSONString(sShippingFee));
        Map<String, Object> map = new HashMap<String, Object>();
        SShippingFeeExample example = new SShippingFeeExample();
        example.setLimitStart(page.getStartIndex());
        example.setLimitEnd(page.getPageSize());
        if (StringUtils.isNotBlank(page.getOrder())) {
            example.setOrderByClause(page.getOrder());
        } else {
            example.setOrderByClause("id ASC");
        }
        try {
            LOGGER.info("select shipping fee list");
            page.setTotalRecord(this.getSShippingFeeMapper().countByExample(example));
            List<SShippingFee> list = this.getSShippingFeeMapper().selectByExample(example);

            map.put("page", page);
            map.put("ShippingFee", list);
        } catch (Exception e) {
            LOGGER.error("select shipping fee list error : {}.", e);
            e.printStackTrace();
        }
        return map;
    }

    @Override
    public BigDecimal queryBaseShippingFee(final BigDecimal distance, List<SShippingFee> fees) {
        LOGGER.info("calculateShippingFee params : {}", distance, fees);
        if (null == distance) {
            LOGGER.error("calculateShippingFee distance is null");
            throw new IllegalArgumentException("运距不能为空");
        }
        if (CollectionUtils.isEmpty(fees)) {
            LOGGER.error("calculateShippingFee fees is empty");
            throw new IllegalArgumentException("费用因子不能为空");
        }

        //阶梯型计算运距运输费
        BigDecimal total = BigDecimal.ZERO.setScale(2);
//		List<SShippingFee> list = fees.stream().filter(fee -> !(1==fee.getBeginRange().compareTo(distance)) && !(-1==fee.getEndRange().compareTo(distance))).collect(Collectors.toList());
        List<SShippingFee> list = fees.stream().filter(fee -> !(1 == fee.getBeginRange().compareTo(distance) && !(-1 == fee.getEndRange().compareTo(distance)))).collect(Collectors.toList());
        list.sort((SShippingFee f1, SShippingFee f2) -> f1.getBeginRange().compareTo(f2.getBeginRange()));

        return recursionCalculate(total, distance, list, 0);
    }

    private BigDecimal recursionCalculate(BigDecimal total, BigDecimal distance, List<SShippingFee> fees, int idx) {
        if (idx < fees.size()) {
            SShippingFee fee = fees.get(idx);
            BigDecimal price = BigDecimal.ZERO;
            if (-1 != distance.compareTo(fee.getEndRange())) {
//				stage = stage.add(fee.getEndRange().subtract(fee.getBeginRange())).add(BigDecimal.valueOf(1));
//				price = fee.getRate().multiply(fee.getEndRange().subtract(fee.getBeginRange()).add(BigDecimal.valueOf(1)));
                price = fee.getUpperLimit();
                if (fee.getUpperLimit().compareTo(BigDecimal.ZERO) == 1) {
                    total = total.add(price.compareTo(fee.getUpperLimit()) == 1 ? fee.getUpperLimit() : price);
                } else {
                    total = total.add(price);
                }
//				return recursionCalculate(total, stage, distance, fees, idx+1);
                return recursionCalculate(total, distance, fees, idx + 1);
            } else {
                if (!(0 == distance.compareTo(BigDecimal.ZERO))) {
                    BigDecimal value = fees.get(idx).getBeginRange().subtract(BigDecimal.valueOf(1));
                    value = !(-1 == value.compareTo(BigDecimal.ZERO)) == true ? value : BigDecimal.ZERO;
                    price = distance.subtract(value).multiply(fee.getRate());
                }
                if (fee.getUpperLimit().compareTo(BigDecimal.ZERO) == 1) {
                    total = total.add(price.compareTo(fee.getUpperLimit()) == 1 ? fee.getUpperLimit() : price.add(fee.getSubsidy()));
                } else {
                    total = total.add(price);
                }
            }
        }
        return total;
    }

    @Override
    public List<SShippingFee> getList(BigDecimal distance) {
        SShippingFeeExample example = new SShippingFeeExample();
        example.createCriteria().andBeginRangeLessThanOrEqualTo(distance);
        return sShippingFeeMapper.selectByExample(example);
    }

    @Override
    public SOrderFeeDetailVo queryVehiclesShippingFee(BigDecimal coefficient, BigDecimal baseFee,
                                                      List<VehiClesInfoFrom> vehicles, BStowageModel stowageModel) {
        LOGGER.info("queryShippingFee params : {}", coefficient, baseFee, JSON.toJSON(vehicles));

        if (null == baseFee) {
            LOGGER.error("queryShippingFee baseFee must not be null");
            throw new IllegalArgumentException("基础运费不能为空");
        }

        //验证参数
        if (CollectionUtils.isEmpty(vehicles)) {
            LOGGER.error("queryShippingFee vehicles must not be null");
            throw new IllegalArgumentException("车型信息不能为空");
        }
        for (int i = 0; i < vehicles.size(); i++) {
            ValidationParams.validation(LOGGER, "queryShippingFee", vehicles.get(i), null);
        }
        //总运费
        BigDecimal total = BigDecimal.ZERO.setScale(2);

        //计算匹配配置模型折扣
        if (null != stowageModel) {
            //满足匹配模型-->打折
            baseFee = baseFee.multiply(stowageModel.getDiscount());
        }

        //根据车型列表返回车型列表系数
        List<String> classes = vehicles.stream().map(ve -> StringUtils.isBlank(ve.getType()) == true ? BVehicleConstant.DEFAULT_VEHICLE_CLASS : ve.getType()).collect(Collectors.toList());
        List<BVehicleClass> vehicleClasses = bVehicleClassService.getLists(classes);
        Map<String, BigDecimal> map = vehicleClasses.stream().collect(Collectors.toMap(BVehicleClass::getVehicleClass, BVehicleClass::getFactorRatio));

        for (int i = 0; i < vehicles.size(); i++) {
            VehiClesInfoFrom info = vehicles.get(i);
            if (null == info.getTypeId()) {
                info.setTypeId(2L);
            }
            total = total.add(baseFee.multiply(map.get(StringUtils.isBlank(info.getType()) == true ? BVehicleConstant.DEFAULT_VEHICLE_CLASS : info.getType())).multiply(BigDecimal.valueOf(info.getAmount())));
        }

        //查询费用类型
        BFeeType feeType = bFeeTypeService.getByCode(bFeeModelService.getByCode(BFeeModelEnum.INTERCITY_ORDER).getId(), Arrays.asList(BFeeTypeEnum.SHIPPING.getValue())).get(0);

        SOrderFeeDetailVo vo = new SOrderFeeDetailVo();
        vo.setId(feeType.getId());
        vo.setFeeCode(feeType.getFeeCode());
        vo.setFeeName(feeType.getFeeName());
        vo.setCost(total.multiply(coefficient).multiply(feeType.getDiscount()).setScale(0, RoundingMode.UP).setScale(2));

        return vo;
    }

}
